package contower

import (
	"github.com/shopspring/decimal"
	"math"
	"math/rand"
	"time"
	"wzgames/internal/constant"
	"wzgames/internal/model/aviatorp"
	"wzgames/pkg/common/timingwheel"
	"wzgames/pkg/utils/calcutil"
	"wzgames/pkg/utils/dateutil"
)

// 小飞机结果运算
// 小飞机播报过程运算

type AMultiplier struct {
	currentMultiplier float64
	fixMultiplier     float64
	currentGameTime   int64
	timestep          int64
	currentRound      *aviatorp.AviatorRound
	interval          time.Duration
	multiTimer        *timingwheel.Timer

	houseEdge   float64
	houseEdgeAj decimal.Decimal
	maxv        int64
	loga        float64
	ma          float64

	core *AirManager
}

func (am *AMultiplier) Init(c *AirManager) error {
	am.core = c
	am.timestep = 100
	am.interval = time.Duration(am.timestep) * time.Millisecond
	rand.Seed(dateutil.UnixNano())
	am.maxv = 4503599627370496
	am.ma = 2.265
	am.loga = math.Log(am.ma)

	return nil
}

func (am *AMultiplier) CurrentMultiplier() float64 {
	return am.fixMultiplier
}

func (am *AMultiplier) SetHouseEdge(houseEdge float64) {
	am.houseEdge = houseEdge
	am.houseEdgeAj = decimal.NewFromInt32(100 - 1).Div(decimal.NewFromInt32(100).Sub(decimal.NewFromFloat(am.houseEdge)))
}

func (am *AMultiplier) Reset() {
	am.currentGameTime = 0
	if am.multiTimer != nil {
		am.multiTimer.Stop()
	}
}

func (am *AMultiplier) Run(rd *aviatorp.AviatorRound) {
	am.currentRound = rd
	am.currentMultiplier = 1.0
	am.fixMultiplier = 1.0
	am.ExpMultiplier(nil)
}

func (am *AMultiplier) calcMultiplier(gametime int64) float64 {
	return math.Pow(am.ma, 0.0001*float64(gametime))
}

func (am *AMultiplier) CalcTotalTime(result float64) int64 {
	if result <= 1 {
		return am.timestep
	}
	y := math.Log(result)
	c := y / am.ma * 10000
	return int64(c)
}

// ExpMultiplier 过程赔率运算，并播报
func (am *AMultiplier) ExpMultiplier(data interface{}) {
	am.currentGameTime += am.timestep
	am.currentMultiplier = am.calcMultiplier(am.currentGameTime)
	if am.currentMultiplier >= am.currentRound.Result {
		am.fixMultiplier = am.currentRound.GetResult()
		am.currentMultiplier = am.currentRound.GetResult()
		am.core.PublishCurrentMultiplier(am.currentRound.RoundId, am.currentMultiplier, am.currentRound.Result, am.currentGameTime, true)
		am.core.changeToState(constant.CrashState)
	} else {
		vfix := calcutil.RoundFloor(am.currentMultiplier)
		am.fixMultiplier = vfix
		am.core.PublishCurrentMultiplier(am.currentRound.RoundId, vfix, am.currentRound.Result, am.currentGameTime, false)
		am.multiTimer = TimerAfter(am.interval, am.ExpMultiplier, nil)
	}
}

// In 1 of 101 result is 0.
func (am *AMultiplier) Divisible(hhex string, mod int64) bool {
	val := int64(0)
	l := len(hhex)
	hmod := l % 4
	idx := 0
	if hmod > 0 {
		idx = hmod - 4
	}
	for ; idx < l; idx += 4 {
		v1 := val << 16
		v2, _ := calcutil.Hex2Dec(hhex[idx : idx+4])
		val = (v1 + v2) % mod
	}

	return val == 0
}

// CalcResult 计算小飞机最终Crash值
// 参考 https://bitcointalk.org/index.php?topic=2807542.msg28716608#msg28716608
func (am *AMultiplier) CalcResult(hdecimal int64, betCount int64, isCtl int) (p, ret decimal.Decimal) {
	//if betCount == 0 && isCtl == constant.NormalStatus {
	//	r := am.multiplierOnZeroBet()
	//	return decimal.NewFromFloat(r), decimal.NewFromFloat(r)
	//}
	p = decimal.NewFromInt(hdecimal).Div(decimal.NewFromInt(am.maxv))
	p = decimal.NewFromInt(99).Div(decimal.NewFromInt(1).Sub(p))
	ret = p.Div(calcutil.BaseCoefficient).Div(am.houseEdgeAj)
	return
}

func (am *AMultiplier) multiplierOnZeroBet() float64 {
	p1 := rand.Int63n(5) + 1
	p2 := rand.Int63n(100)
	return float64(p1) + calcutil.CalcIntDiv100(p2)
}
